package jk.framework.spring.security;

import jk.framework.spring.security.authorization.DynamicDecisionVoter;
import jk.framework.spring.security.authorization.DynamicSecurityMetadataSource;
import jk.framework.spring.security.authorization.SecurityResourcesService;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.ConsensusBased;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

/**
 * 动态权限配置
 *
 * @author cuichao
 */
public class DynamicAuthorizationConfig {
    /**
     * 一致决议器: 所有Voter一致通过才放行
     */
    private final static String UNANIMOUS_STRATEGY = "unanimous";
    /**
     * 共识决议器：大部分voter通过就放行
     */
    private final static String CONSENSUS_STRATEGY = "consensus";
    /**
     * 肯定决议器: 只要有一个voter通过放行
     */
    private final static String AFFIRMATIVE_STRATEGY = "affirmative";
    /**
     * 投票管理器
     */
    private AccessDecisionManager decisionManager;
    /**
     * 系统权限资源服务
     */
    private SecurityResourcesService resourcesService;
    /**
     * 系统权限数据源
     */
    private FilterInvocationSecurityMetadataSource metadataSource;
    /**
     * 任务请求访问权限
     */
    private String anyRequestAccess = BaseAccess.authenticated;
    /**
     * 投票策略
     */
    private String decisionStrategy = AFFIRMATIVE_STRATEGY;


    private List<AccessDecisionVoter<?>> voters;

    {
        voters = new ArrayList<>();
        voters.add(new DynamicDecisionVoter());
    }

    /**
     * 完成配置
     */
    void configure() {

        Assert.notNull(this.resourcesService, "the " + SecurityResourcesService.class.getName() + "implements is not null");

        switch (decisionStrategy) {
            case UNANIMOUS_STRATEGY:
                this.decisionManager = new UnanimousBased(voters);
                break;
            case CONSENSUS_STRATEGY:
                this.decisionManager = new ConsensusBased(voters);
                break;
            case AFFIRMATIVE_STRATEGY:
            default:
                this.decisionManager = new AffirmativeBased(voters);
        }
        this.metadataSource = new DynamicSecurityMetadataSource(this.resourcesService, this.anyRequestAccess);
    }


    /**
     * 获取投票管理器
     *
     * @return
     */
    AccessDecisionManager getDecisionManager() {
        return this.decisionManager;
    }

    /**
     * 获取服务器权限资源
     *
     * @return
     */
    FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return metadataSource;
    }

    /**
     * 添加权限访问投票器
     *
     * @param voter
     * @return
     */
    public DynamicAuthorizationConfig addAccessDecisionVoter(AccessDecisionVoter<?> voter) {
        voters.add(voter);
        return this;
    }


    public DynamicAuthorizationConfig resourcesService(SecurityResourcesService resourcesService) {
        this.resourcesService = resourcesService;
        return this;
    }
    /**
     * 确定投票管理器策略
     *
     * @return
     */
    public DynamicDecisionStrategy decisionManagerStrategy() {
        return new DynamicDecisionStrategy();
    }

    /**
     * 设置所有请求基础权限(匹配到权限的URL不会用到该权限)
     *
     * @return
     */
    public AnyRequestAccessor anyRequest() {
        return new AnyRequestAccessor();
    }


    /**
     * 投票管理策略类
     */
    public class DynamicDecisionStrategy {

        public DynamicAuthorizationConfig unanimous() {
            decisionStrategy = UNANIMOUS_STRATEGY;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig consensus() {
            decisionStrategy = CONSENSUS_STRATEGY;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig affirmative() {
            decisionStrategy = AFFIRMATIVE_STRATEGY;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig and() {
            return DynamicAuthorizationConfig.this;
        }
    }


    public class AnyRequestAccessor {

        public DynamicAuthorizationConfig denyAll() {
            anyRequestAccess = BaseAccess.denyAll;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig permitAll() {
            anyRequestAccess = BaseAccess.permitAll;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig authenticated() {
            anyRequestAccess = BaseAccess.authenticated;
            return DynamicAuthorizationConfig.this;
        }

        public DynamicAuthorizationConfig fullyAuthenticated() {
            anyRequestAccess = BaseAccess.fullyAuthenticated;
            return DynamicAuthorizationConfig.this;
        }


    }


}
